/**
 * 
 */
package com.ekingstar.framework.service.impl;

import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.ekingstar.framework.domain.Function;
import com.ekingstar.framework.domain.FunctionField;
import com.ekingstar.framework.domain.Role;
import com.ekingstar.framework.domain.RoleDataRight;
import com.ekingstar.framework.domain.RoleFunction;
import com.ekingstar.framework.domain.RoleFunctionField;
import com.ekingstar.framework.domain.RoleFunctionParamValue;
import com.ekingstar.framework.domain.User;
import com.ekingstar.framework.domain.UserRole;
import com.ekingstar.framework.security.UserUtil;
import com.ekingstar.framework.service.ChangeFunctionEvent;
import com.ekingstar.framework.service.IFunctionService;
import com.ekingstar.framework.service.IRoleService;
import com.ekingstar.framework.service.RoleExistException;
import com.ekingstar.framework.util.HibernateCallbackUtil;
import com.ekingstar.framework.util.Page;

/**
 * 
 *
 */
public class RoleServiceImpl implements IRoleService,ApplicationEventPublisherAware {
	
	private static Logger log = LoggerFactory.getLogger(RoleServiceImpl.class);
	private HibernateTemplate hibernateTemplate;
	private IFunctionService functionService;
	public void setFunctionService(IFunctionService functionService) {
		this.functionService = functionService;
	}
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
	/* (non-Javadoc)
	 * @see com.ekingstar.framework.service.IRoleService#addRole(com.ekingstar.framework.domain.Role)
	 */
	public boolean addRole(Role role) {
		// TODO Auto-generated method stub
		if (role == null || role.getId() != null) return false;
		if (role.getName().indexOf("ROLE_") < 0){
			role.setName("ROLE_"+role.getName());
		}
		checkExistRole(role.getName());
		role.setAdderId(UserUtil.getCurrentUserId());
		role.setAddDate(new Date());
		hibernateTemplate.save(role);
		//
		List res = hibernateTemplate.findByNamedParam("select count(*) from UserRole a where a.deleteDate is null and " +
				" a.TRole.name='ROLE_ADMIN' and a.TUser.id =:uId", "uId", UserUtil.getCurrentUserId());
		if (res != null || !res.isEmpty()){
			Number count = (Number)res.get(0);
			if (count.intValue() > 0 ){
				UserRole ur = new UserRole();
				ur.setTRole(role);
				ur.setTUser(new User(UserUtil.getCurrentUserId()));
				ur.setAddDate(new Date());
				ur.setAdderId(UserUtil.getCurrentUserId());
				ur.setCanGrant(Boolean.TRUE);
				hibernateTemplate.save(ur);
			}
		}
		
		return true;
	}

	/* (non-Javadoc)
	 * @see com.ekingstar.framework.service.IRoleService#deleteRole(java.lang.String)
	 */
	public boolean deleteRole(String id) {
		// TODO Auto-generated method stub
		if (id == null || id.trim().equals("")) return false;
		Role role = (Role)hibernateTemplate.get(Role.class, id);
		role.setDeleterId(UserUtil.getCurrentUserId());
		role.setDeleteDate(new Date());
		hibernateTemplate.save(role);
		return true;
	}

	/* (non-Javadoc)
	 * @see com.ekingstar.framework.service.IRoleService#queryRoles(com.ekingstar.framework.domain.Role, int, int)
	 */
	public Page queryRoles(Role contion, int pageNo, int pageSize) {
		// TODO Auto-generated method stub
		StringBuffer sb = new StringBuffer(" from Role a where a.deleteDate is null ");
		Map params = new HashMap();
		if (pageNo <= 0 ) pageNo = 1;
		if (contion != null ){
			if (contion.getName() != null && !contion.getName().trim().equals("")){
				sb.append(" and a.name like :name ");
				params.put("name","%"+contion.getName().trim()+"%");
			}
			if (contion.getDetail() != null && !contion.getDetail().trim().equals("")){
				sb.append(" and a.detail like :detail ");
				params.put("detail","%"+contion.getDetail().trim()+"%");
			}
		}
		HibernateCallback action = HibernateCallbackUtil.getCallbackWithPage(sb, params, null, pageNo, pageSize);
		Page page  = (Page)hibernateTemplate.execute(action);
		return page;
	}

	/* (non-Javadoc)
	 * @see com.ekingstar.framework.service.IRoleService#updateRole(com.ekingstar.framework.domain.Role)
	 */
	public boolean updateRole(Role role) {
		if (role == null || role.getId() == null || role.getId().trim().equals("")) return false;
		if (role.getName().indexOf("ROLE_") < 0){
			role.setName("ROLE_"+role.getName());
		}
		Role orole = (Role)hibernateTemplate.get(Role.class, role.getId());
		if (!role.getName().equals(orole.getName())){
			checkExistRole(role.getName());
			orole.setName(role.getName());
		}
		orole.setUpdaterId(UserUtil.getCurrentUserId());
		orole.setLastUpdateDate(new Date());
		orole.setDetail(role.getDetail());
		hibernateTemplate.save(orole);
		return true;
	}

	/* (non-Javadoc)
	 * @see com.ekingstar.framework.service.IRoleService#viewRole(java.lang.String)
	 */
	public Role viewRole(String id) {
		// TODO Auto-generated method stub
		if (id == null || id.trim().equals("")) return null;
		Role role = (Role)hibernateTemplate.get(Role.class, id);
		List users = hibernateTemplate.findByNamedParam("select a  from User a where a.deleteDate is null and a.id in" +
				"  ( select a.TUser.id from UserRole a where a.deleteDate is null and  a.TRole.id=:id )", "id", id);
		List functions  = hibernateTemplate.findByNamedParam("select a  from Function a where a.deleteDate is null and a.id in" +
				"  ( select a.TFunction.id from RoleFunction a where a.deleteDate is null and  a.TRole.id=:id )", "id", id);
		//
		if (functions != null  && functions.size() > 0){
			for (int i = 0; i < functions.size();i++){
				Function fun = (Function)functions.get(i);
				fun = functionService.viewFunction(fun.getId());
				//如果角色拥有该字段则 选中
				if (fun != null || fun.getFields() != null && fun.getFields().size()>0){
					for (int j =0 ; j < fun.getFields().size();j++){
						FunctionField ff = (FunctionField)fun.getFields().get(j);
						List t = hibernateTemplate.findByNamedParam("select a.id  " +
								" from RoleFunctionField a where a.deleteDate is null" +
								"  and a.roleFunction.TRole=:role and a.functionField=:ff ", new String[]{"role","ff"}, new Object[]{role,ff});
						if (t != null && t.size() > 0){
							ff.setSelected(Boolean.TRUE);
						}
					}
				}
			}
		}
		
		//
		role.setUsers(users);
		role.setFunctions(functions);
		return role;
	}

	private void checkExistRole(String roleName){
		if (roleName == null || roleName.trim().equals("")) return;
		List res = hibernateTemplate.findByNamedParam("select count(*) from Role a " +
				" where a.name=:name and a.deleteDate is null ", "name", roleName.trim()); 
		if (res != null && res.size() > 0){
			Number count = (Number)res.get(0);
			if (count.intValue() > 0) throw new RoleExistException("�ù����Ѿ�����!");
		}
	}
	public List<Function> getFunctionsByRoleId(String id) {
		// TODO Auto-generated method stub
		if(id == null || id.trim().equals("")) return null;
		return hibernateTemplate.findByNamedParam(" from Function a where a.deleteDate is null and " +
				" a.id in ( select a.TFunction.id  from RoleFunction a where  a.deleteDate is null and a. TRole.id=:id ) ", "id", id);
	}
	public boolean grantFunctionToRole(final Role r) {
		// TODO Auto-generated method stub
		if (r == null || r.getId() == null || r.getId().trim().equals("")) return false;
		final Role orole  = (Role)hibernateTemplate.get(Role.class, r.getId());
		if (orole == null) return false;
		hibernateTemplate.execute(new HibernateCallback(){
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query q = session.createQuery("update RoleFunctionField a set a.deleteDate=:now ,a.deleterId=:uId " +
						" where a.roleFunction in (select b from RoleFunction b where b.TRole=:role)");
				q.setParameter("now", new Date());
				String uId = UserUtil.getCurrentUserId();
				q.setParameter("uId",uId);
				q.setParameter("role", orole);
				q.executeUpdate();
				//
				q = session.createQuery("update RoleFunction a set a.deleteDate=:now ,a.deleterId=:uId where a.TRole=:role");
				q.setParameter("now", new Date());
				q.setParameter("uId",uId);
				q.setParameter("role", orole);
				q.executeUpdate();
				//
				List functions = r.getFunctions();
				if (functions == null || functions.isEmpty()) return null;
				for (int i = 0 ;i < functions.size() ;i ++){
					Function f = (Function)functions.get(i);
					if (f == null || f.getId()==null) continue;
					RoleFunction rf = new RoleFunction();
					rf.setTRole(orole);
					rf.setTFunction(f);
					rf.setAddDate(new Date());
					rf.setAdderId(uId);
					session.save(rf);
					if (f.getFields() == null) continue;
					for (int j = 0; j < f.getFields().size();j++){
						FunctionField ff = (FunctionField)f.getFields().get(j);
						RoleFunctionField rff = new RoleFunctionField();
						rff.setRoleFunction(rf);
						rff.setFunctionField(ff);
						rff.setAddDate(new Date());
						rff.setAdderId(uId);
						session.save(rff);
					}
				}
				return null;
			}
			
		});
		applicationEventPublisher.publishEvent(new ChangeFunctionEvent(this));
		return true;
	}
	
	public List getRoleByUserId(String uid) {
		StringBuffer sb = new StringBuffer("select a.TRole.id as id,a.TRole.name as name,a.TRole.detail as detail, a.canUse as canUse, a.canGrant as  canGrant" +
				" from UserRole a where a.deleteDate is null and a.TUser.id=:uid ");
		Map params = new HashMap();
		params.put("uid", uid);
		HibernateCallback action =  HibernateCallbackUtil.getCallback(sb, params, false, Transformers.aliasToBean(Role.class));
		List roles = (List)hibernateTemplate.execute(action);
		return roles;
	}
	
	
	public List getCanGrantRoles(String uid) {
		StringBuffer sb = new StringBuffer("select a.TRole.id as id,a.TRole.name as name " +
		" from UserRole a where a.deleteDate is null and a.TRole.deleteDate is null and a.TUser.id=:uid  and a.canGrant=:canGrant");
		Map params = new HashMap();
		params.put("uid", uid);
		params.put("canGrant", Boolean.TRUE);
		HibernateCallback action =  HibernateCallbackUtil.getCallback(sb, params, false, Transformers.aliasToBean(Role.class));
		List roles = (List)hibernateTemplate.execute(action);
		return roles;
	}
	public List getFieldsByRoleId(String roleId, String funId) {
		// TODO Auto-generated method stub
		if (roleId == null || roleId.trim().equals("")) return null;
		StringBuffer sb = new StringBuffer("select a " +
		" from FunctionField a,RoleFunctionField b,RoleFunction c,Role d,Function e " +
		"  where a.deleteDate is null and b.deleteDate is null and c.deleteDate is null " +
		"  and  b.functionField=a and b.roleFunction=c " +
		"  and c.TRole=d and c.TFunction = e and d.id=:rId ");
		Map params = new HashMap();
		params.put("rId", roleId);
		if (funId != null && !funId.trim().equals("")){
			sb.append(" and e.id=:fId ");
			params.put("fId",funId);
		}
		HibernateCallback action =  HibernateCallbackUtil.getCallback(sb, params, false, null);
		List fields = (List)hibernateTemplate.execute(action);
		return fields;
	}
	public boolean grantRowDataRihgtToRole(final Role r) {
		// TODO Auto-generated method stub
		if (r == null || r.getId() == null) return false;
		hibernateTemplate.execute(new HibernateCallback(){
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				// TODO Auto-generated method stub
				Date now = new Date();
				Query query = session.createQuery(" update  RoleDataRight a set a.deleterId=:uId ,a.deleteDate=:now where a.roleId=:rId");
				query.setParameter("uId", UserUtil.getCurrentUserId());
				query.setParameter("rId", r.getId());
				query.setParameter("now", now);
				query.executeUpdate();
				//
				if (r.getRowDataRights() != null ){
					now = new Date();
					for (int i = 0; i < r.getRowDataRights().size();i++){
						RoleDataRight rdr = (RoleDataRight)r.getRowDataRights().get(i);
						if (rdr.getRightId() != null && !rdr.getRightId().trim().equals("")){
							rdr.setAddDate(now);
							rdr.setAdderId(UserUtil.getCurrentUserId());
							rdr.setRoleId(r.getId());
							session.save(rdr);
						}
					}
				}
				return null;
			}
		});
		return true;
	}
	public List getRowDataRightByRoleId(String roleId) {
		// TODO Auto-generated method stub
		return hibernateTemplate.findByNamedParam("select a from SystemParameter a ,RoleDataRight b "  +
				"  where b.deleteDate is null and b.roleId=:rId and b.rightId=a.id ", "rId", roleId); 
	}
	public List<Role> getAllRoles() {
		// TODO Auto-generated method stub
		return this.hibernateTemplate.find(" from Role a where a.deleteDate is null order by a.addDate desc ");
	}
	public void setApplicationEventPublisher(
			ApplicationEventPublisher applicationEventPublisher) {
		// TODO Auto-generated method stub
		this.applicationEventPublisher = applicationEventPublisher;
		
	}
	private ApplicationEventPublisher applicationEventPublisher = null;
	public boolean grantFunctionParamsToRole(final Role r) {
		// TODO Auto-generated method stub
		if (r == null || r.getId() == null || r.getId().trim().equals("")) return false;
		if (r.getFunctionParamValues() == null || r.getFunctionParamValues().isEmpty()) return false;
		List pvs = r.getFunctionParamValues();
		for (int i = 0;i < pvs.size();i++){
			RoleFunctionParamValue pv = (RoleFunctionParamValue) pvs.get(i);
			final String paramId = pv.getParamId();
			//删除该值
			hibernateTemplate.execute(new HibernateCallback() {
				public Object doInHibernate(Session session) throws HibernateException,
						SQLException {
					// TODO Auto-generated method stub
					Query query = session.createQuery("delete from RoleFunctionParamValue a where a.roleId=:rId and a.paramId=:pId");
					query.setParameter("rId", r.getId().trim());
					query.setParameter("pId", paramId.trim());
					query.executeUpdate();
					return null;
				}
			});
			if (pv.getParamValue() != null && !pv.getParamValue().trim().equals("")){
				//值不空时添加
				pv.setRoleId(r.getId());
				pv.setIsvalid("1");
				hibernateTemplate.save(pv);
			}
		}
		return true;
	}
	
	
}
